home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 July
/
EnigmA AMIGA RUN 09 (1996)(G.R. Edizioni)(IT)[!][issue 1996-07 & 08][EARSAN CD VIII].iso
/
earcd
/
dev1
/
vbcc.lha
/
vbcc
/
opt.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-05-15
|
21KB
|
497 lines
/* $VER: vbcc (opt.c) V0.3 */
/* allgemeine Routinen fuer den Optimizer und Steuerung der einzelnen */
/* Laeufe */
#include "opt.h"
/* die naechsten Funktionen sollten evtl. in ic.c */
void insert_IC(struct IC *p,struct IC *new)
/* fuegt new hinter p ein; p darf 0 sein */
{
new->prev=p;
if(p){ new->next=p->next; p->next=new; }
else{ new->next=first_ic; first_ic=new; }
if(new->next) new->next->prev=new; else last_ic=new;
new->q1.am=new->q2.am=new->z.am=0;
}
#ifndef NO_OPTIMIZER
int gchanged; /* Merker, ob Optimierungslauf etwas geaendert hat */
int norek; /* diese Funktion wird nicht rekursiv auf */
int nocall; /* diese Funktion kehrt nicht zum Caller zurueck */
/* temporary fuer verschiedene Bitvektoren */
unsigned char *tmp;
void recalc_offsets(struct flowgraph *fg)
/* berechnet Offsets fuer auto-Variablen neu und versucht, fuer Variablen, */
/* die nicht gleichzeitig aktiv sind, den gleichen Platz zu belegen */
{
int i,b,*al,*sz,*eqto;size_t bsize;
unsigned char **used,*tmp,*empty;
struct IC *p;
if(DEBUG&1024) printf("recalculating offsets\n");
if(DEBUG&1024) printf("setting up arrays\n");
bsize=(basic_blocks+CHAR_BIT-1)/CHAR_BIT;
if(DEBUG&1024) printf("bsize=%d\n",bsize);
tmp=mymalloc(bsize);
al=mymalloc(sizeof(int)*(vcount-rcount));
eqto=mymalloc(sizeof(int)*(vcount-rcount));
sz=mymalloc(sizeof(int)*(vcount-rcount));
empty=mymalloc(bsize);
memset(empty,0,bsize);
used=mymalloc(sizeof(unsigned char *)*(vcount-rcount));
/* Tabelle, welche Variable in welchem Block belegt ist, aufbauen */
for(i=0;i<vcount-rcount;i++){
if(vilist[i]->offset>=0&&(vilist[i]->storage_class==AUTO||vilist[i]->storage_class==REGISTER)){
if(DEBUG&2048) printf("setting up for %s,%d\n",vilist[i]->identifier,vilist[i]->offset);
used[i]=mymalloc(bsize);
memset(used[i],0,bsize);
}else{
used[i]=0;
}
sz[i]=szof(vilist[i]->vtyp);
al[i]=align[vilist[i]->vtyp->flags&15];
eqto[i]=-1;
}
b=0;
while(fg){
if(b>=basic_blocks) ierror(0);
for(i=0;i<vcount-rcount;i++){
if(used[i]&&(BTST(fg->av_in,i)||BTST(fg->av_out,i))){
int r;
BSET(used[i],b);
for(r=1;r<=MAXR;r++)
if(fg->regv[r]&&fg->regv[r]->index==i) BCLR(used[i],b);
}
}
for(p=fg->start;p;p=p->next){
if((p->q1.flags&(VAR|REG))==VAR){
i=p->q1.v->index;
if(used[i]){
BSET(used[i],b);
}
}
if((p->q2.flags&(VAR|REG))==VAR){
i=p->q2.v->index;
if(used[i]){
BSET(used[i],b);
}
}
if((p->z.flags&(VAR|REG))==VAR){
i=p->z.v->index;
if(used[i]){
BSET(used[i],b);
}
}
if(p==fg->end) break;
}
fg=fg->normalout;
b++;
}
/* schauen, ob Variablen in gleichen Speicher koennen */
if(DEBUG&1024) printf("looking for distinct variables\n");
for(i=0;i<vcount-rcount;i++){
if(!used[i]||eqto[i]>=0) continue;
for(b=i+1;b<vcount-rcount;b++){
if(!used[b]||eqto[b]>=0) continue;
if(DEBUG&2048) printf("comparing %s(%d) and %s(%d)\n",vilist[i]->identifier,vilist[i]->offset,vilist[b]->identifier,vilist[b]->offset);
memcpy(tmp,used[i],bsize);
bvintersect(tmp,used[b],bsize);
if(!memcmp(tmp,empty,bsize)){
if(DEBUG&1024) printf("memory for %s(%d) and %s(%d) equal\n",vilist[i]->identifier,vilist[i]->offset,vilist[b]->identifier,vilist[b]->offset);
eqto[b]=i;
if(al[b]>al[i]) al[i]=al[b];
if(sz[b]>sz[i]) sz[i]=sz[b];
bvunite(used[i],used[b],bsize);
}
}
}
if(DEBUG&1024) printf("final recalculating\n");
max_offset=0;
for(i=0;i<vcount-rcount;i++){
if(!used[i]) continue;
free(used[i]);
if(DEBUG&2048) printf("adjusting offset for %s,%d\n",vilist[i]->identifier,vilist[i]->offset);
if(eqto[i]>=0){
vilist[i]->offset=vilist[eqto[i]]->offset;
continue;
}
vilist[i]->offset=((max_offset+al[i]-1)/al[i])*al[i];
max_offset=vilist[i]->offset+sz[i];
}
free(used);
free(sz);
free(al);
free(tmp);
free(empty);
free(eqto);
}
void remove_IC_fg(struct flowgraph *g,struct IC *p)
/* entfernt IC p und beachtet Flussgraph */
{
if(p->q1.am||p->q2.am||p->z.am) ierror(0);
if(g->start==g->end){
g->start=g->end=0;
}else{
if(p==g->end) g->end=p->prev;
if(p==g->start) g->start=p->next;
}
remove_IC(p);
}
int peephole(void)
/* macht alle moeglichen Vereinfachungen/Vereinheitlichungen */
{
struct IC *p;struct obj o;int t,c,null,eins,changed,done=0;
do{
if(DEBUG&1024) printf("searching for peephole optimizations\n");
changed=0;ic_count=0;
p=first_ic;
while(p){
c=p->code;
t=p->typf;
ic_count++;
if(p->q1.flags&KONST){
if((p->q2.flags&KONST)||!p->q2.flags){
struct IC *old=p->prev;
if(fold(p)){ changed=1; p=old;continue;}
p=p->next;continue;
}else{
if(c==ADD||c==MULT||(c>=OR&&c<=AND)){ /* const nach rechts */
if(DEBUG&1024){ printf("swapped commutative op:\n");pric2(stdout,p);}
o=p->q1;p->q1=p->q2;p->q2=o;
}
}
}
if(p->q2.flags&KONST){
/* algebraische Optimierungen */
eval_const(&p->q2.val,t);
if(zleq(vlong)&&zuleq(vulong)&&zdeq(vdouble)) null=1; else null=0;
if(zleqto(vlong,l2zl(1L))&&zuleqto(vulong,ul2zul(1UL))&&zdeqto(vdouble,d2zd(1.0))) eins=1; else eins=0;
if(zleqto(vlong,l2zl(-1L))&&zdeqto(vdouble,d2zd(-1.0))) eins=-1;
if(eins<0&&(c==MULT||c==DIV)){
if(DEBUG&1024){ printf("MULT/DIV with (-1) converted to MINUS:\n");pric2(stdout,p);}
p->code=MINUS;p->q2.flags=0;
changed=1;
}
#if 0
if(c==SUB){
/* VORSICHT: Das funktioniert bei bestimmten Werten nicht! */
if(DEBUG&1024){ printf("SUB converted to ADD:\n");pric2(stdout,p);}
p->code=ADD; calc(MINUS,t,&p->q2.val,0,&p->q2.val);
changed=1;
}
#endif
if((eins>0&&(c==MULT||c==DIV))||(null&&(c==ADD||c==SUB||c==ADDI2P||c==LSHIFT||c==RSHIFT||c==OR||c==XOR))){
if(DEBUG&1024){ printf("operation converted to simple assignment:\n");pric2(stdout,p);}
p->code=ASSIGN;p->q2.flags=0;p->q2.reg=sizetab[t&15];
changed=1;
}
if(null&&(c==MULT||c==DIV||c==MOD||c==AND)){
if(c==DIV||c==MOD) error(84);
if(DEBUG&1024){ printf("operation converted to ASSIGN 0:\n");pric2(stdout,p);}
o.val.vlong=l2zl(0L);eval_const(&o.val,LONG);
insert_const2(&p->q1.val,t);p->q1.flags=KONST;
p->code=ASSIGN;p->q2.flags=0;p->q2.reg=sizetab[t&15];
changed=1;
}
if((t&15)<=LONG&&(c==ADD||c==ADDI2P||c==MULT||c==LSHIFT||c==RSHIFT||c==OR||c==AND)){
/* assoziative Operatoren */
struct IC *n=p->next;
if(n&&n->code==c&&(n->q2.flags&KONST)&&n->typf==t&&n->q1.flags==p->z.flags&&n->q1.v==p->z.v&&zleqto(n->q1.val.vlong,p->z.val.vlong)){
if(DEBUG&1024){ printf("using associativity with:\n");pric2(stdout,p);pric2(stdout,p->next);}
n->q1=p->q1;
if(c==LSHIFT||c==RSHIFT||c==ADDI2P)
calc(ADD,t,&p->q2.val,&n->q2.val,&n->q2.val);
else
calc(c,t,&p->q2.val,&n->q2.val,&n->q2.val);
changed=1;
if(p->q1.flags==p->z.flags&&p->q1.v==p->z.v&&zleqto(p->q1.val.vlong,p->z.val.vlong)){
if(DEBUG&1024) printf("must remove first operation\n");
n=p;p=p->next;remove_IC(n);continue;
}
}
}
if((c==ADDI2P||c==SUBIFP)&&(p->q1.flags&VARADR)){
/* add #var,#const -> move #var+const */
union atyps val;
if(DEBUG&1024){printf("add/sub #var,#const changed to assign:\n");pric2(stdout,p);}
eval_const(&p->q2.val,t);
insert_const2(&val,LONG);
if(c==ADDI2P) calc(ADD,LONG,&p->q1.val,&val,&p->q1.val);
else calc(SUB,LONG,&p->q1.val,&val,&p->q1.val);
p->code=ASSIGN;
p->q2.flags=0;
p->q2.reg=sizetab[t&15];
changed=1;
}
if((c==ADD||c==SUB)&&(t&15)<=LONG&&p->next&&p->next->next){
struct IC *p1=p->next,*p2=p1->next;
if(p1->code==MULT&&p2->code==ADDI2P&&
p1->typf==t&&p2->typf==t&&
(p1->q2.flags&KONST)&&(p->z.flags&SCRATCH)&&(p1->z.flags&SCRATCH)&&
!compare_objs(&p->z,&p1->q1,t)&&
!compare_objs(&p1->z,&p2->q2,t)){
if(DEBUG&1024){ printf("rearranging array-access:\n");pric2(stdout,p);pric2(stdout,p1);pric2(stdout,p2);}
p1->q1=p->q1;
p->q1=p2->q1;
p2->q1=p2->z;
p->z=p2->z;
calc(MULT,t,&p->q2.val,&p1->q2.val,&p->q2.val);
if(c==ADD) p->code=ADDI2P; else p->code=SUBIFP;
changed=1;continue;
}
}
}
if(p->q1.flags&KONST){
/* algebraische Optimierungen */
eval_const(&p->q1.val,t);
if(zleq(vlong)&&zuleq(vulong)&&zdeq(vdouble)) null=1; else null=0;
if(null&&(c==DIV||c==MOD||c==LSHIFT||c==RSHIFT)){
if(DEBUG&1024){ printf("operation converted to ASSIGN 0:\n");pric2(stdout,p);}
o.val.vlong=l2zl(0L);eval_const(&o.val,LONG);
insert_const2(&p->q1.val,t);p->q1.flags=KONST;
p->code=ASSIGN;p->q2.flags=0;p->q2.reg=sizetab[t&15];
changed=1;
}
}
if(!USEQ2ASZ&&p->z.flags&&!compare_objs(&p->q2,&p->z,p->typf)){
if(c==ADD||c==MULT||(c>=OR&&c<=AND)){
struct obj o;
if(DEBUG&1024){printf("swapping objs because USEQ2ASZ\n");pric2(stdout,p);}
o=p->q2;p->q2=p->q1;p->q1=o;
/* kein changed hier! */
}else{pric2(stdout,p); ierror(0);}
}
if((c==ADD||c==SUB)&&p->next){
struct IC *p1=p->next;
if(p1->code==ADDI2P&&p1->typf==t&&(p->z.flags&SCRATCH)&&!compare_objs(&p->z,&p1->q2,t)){
if(DEBUG&1024){ printf("rearranging array-access:\n");pric2(stdout,p);pric2(stdout,p1);}
p1->q2=p->q1;
p->q1=p1->q1;
p->z=p1->z;
p1->q1=p1->z;
if(c==ADD) p->code=ADDI2P; else p->code=SUBIFP;
changed=1;continue;
}
}
if(c==ASSIGN&&(p->z.flags&VAR)&&p->z.flags==p->q1.flags&&p->z.v==p->q1.v&&zleqto(p->z.val.vlong,p->q1.val.vlong)){
struct IC *d;
if(DEBUG&1024){ printf("removing redundant move:\n");pric2(stdout,p);}
changed=1;
d=p; p=p->next; remove_IC(d); continue;
}
p=p->next;
}
if(changed) done|=changed;
gchanged|=changed;
}while(changed);
return(done);
}
#endif
#define FREEAV free(av_globals);free(av_statics);free(av_drefs);free(av_address);
void optimize(long flags,struct Var *function)
/* flags: 1=Register, 2=optimize, 4=cse/cp, 8=constant_propagation, */
/* 16=dead_assignments, 32=global-optimizations */
/* 64=blockweise Registervergabe */
{
#ifndef NO_OPTIMIZER
struct flowgraph *fg=0;int r,pass=0;
if(!(c_flags[11]&USEDFLAG)) c_flags_val[11].l=10;
if(!function) ierror(0);
norek=nocall=0;
report_weird_code=1;
if(!strcmp(function->identifier,"main")){norek=1;nocall=1;}
/* falls main() rekursiv aufgerufen werden kann, muss nomain==0 sein */
#else
flags&=1;
#endif
if(flags&2){
#ifndef NO_OPTIMIZER
/* nur ein pass, wenn nur lokale Optimierungen */
if(!(flags&32)) c_flags_val[11].l=1;
do{
gchanged=0;pass++;
av_globals=av_statics=av_address=av_drefs=0;
rd_globals=rd_statics=rd_address=rd_drefs=0;
ae_globals=ae_statics=ae_address=ae_drefs=0;
cp_globals=cp_statics=cp_address=cp_drefs=0;
dlist=0;vilist=0;elist=0;rd_parms=0;
if(DEBUG&1024) printf("\noptimizer (function %s) pass %d\n",function->identifier,pass);
num_vars();
peephole();
fg=jump_optimization();
if(DEBUG&2048) print_vi();
if(flags&8){
do{
int i;
num_defs();
if(flags&32){
reaching_definitions(fg);
if(DEBUG&1024) print_flowgraph(fg);
}
r=constant_propagation(fg,flags&32);
if(DEBUG&1024) {printf("constant_propagation returned %d\n",r);print_flowgraph(fg);}
if(r){
if(peephole()){free_flowgraph(fg);fg=jump_optimization();}
}
}while(r);
}
if(flags&4){
int repeat;
do{
num_exp();
if(DEBUG&1024) print_flowgraph(fg);
repeat=r=cse(fg,0); /* local cse */
if(DEBUG&1024) printf("local cse returned %d\n",r);
gchanged|=r;
if(r){ /* neue Variablen eingefuegt */
if(DEBUG&1024) printf("must repeat num_vars\n");
free(vilist);
FREEAV;
num_vars();
}
num_copies();
if(DEBUG&1024) print_flowgraph(fg);
r=copy_propagation(fg,0); /* copy propagation */
if(DEBUG&1024) printf("local copy propagation returned %d\n",r);
if(r&2){
if(DEBUG&1024) printf("must repeat num_vars\n");
free(vilist);
FREEAV;
num_vars();
}
gchanged|=r;repeat|=r;
}while(repeat);
if(flags&32){
num_exp();
if(DEBUG&1024) print_flowgraph(fg);
available_expressions(fg);
r=cse(fg,1);gchanged|=r;
if(DEBUG&1024) printf("global cse returned %d\n",r);
if(r){ /* neue Variablen eingefuegt */
if(DEBUG&1024) printf("must repeat num_vars\n");
free(vilist);
FREEAV;
num_vars();
gchanged|=r;
do{
num_copies();
if(DEBUG&1024) print_flowgraph(fg);
r=copy_propagation(fg,0); /* copy propagation */
if(DEBUG&1024) printf("local copy propagation returned %d\n",r);
if(r&2){
if(DEBUG&1024) printf("must repeat num_vars\n");
free(vilist);
FREEAV;
num_vars();
}
gchanged|=r;
}while(r);
}
num_copies();
if(DEBUG&1024) print_flowgraph(fg);
available_copies(fg);
r=copy_propagation(fg,1); /* copy propagation */
if(DEBUG&1024) printf("global copy propagation returned %d\n",r);
if(r&2){
if(DEBUG&1024) printf("must repeat num_vars\n");
free(vilist);
FREEAV;
num_vars();
}
gchanged|=r;
}
}
if((flags&16)||((flags&1)&&pass>=c_flags_val[11].l)){
/* num_vars();*/
active_vars(fg);
if(DEBUG&1024) print_flowgraph(fg);
if((flags&16)&&pass<=c_flags_val[11].l){
r=dead_assignments(fg);
if(DEBUG&1024) printf("dead_assignments returned %d\n",r);
gchanged|=r;
}
}
if((!gchanged||pass>=c_flags_val[11].l)){
/* Funktion evtl. fuer inlining vorbereiten und */
/* Registervergabe */
/* default-Wert fuer inline-Entscheidung */
if(!(c_flags[12]&USEDFLAG)) c_flags_val[12].l=30;
if((c_flags[0]&USEDFLAG)&&(c_flags_val[0].l&4096)&&(only_inline||ic_count<=c_flags_val[12].l)){
/* fuer function inlinig vorbereiten */
struct IC *p,*new;
if(DEBUG&1024) printf("function <%s> prepared for inlining(ic_count=%d)\n",function->identifier,ic_count);
function->fi=mymalloc(sizeof(struct function_info));
function->fi->first_ic=first_ic;
function->fi->last_ic=last_ic;
first_ic=last_ic=0;
p=function->fi->first_ic;
while(p){
new=mymalloc(ICS);
memcpy(new,p,ICS);
if((p->code>=BEQ&&p->code<=BRA)||p->code==LABEL)
new->typf-=lastlabel;
add_IC(new);
p=p->next;
}
p=first_ic;first_ic=function->fi->first_ic;function->fi->first_ic=p;
p=last_ic;last_ic=function->fi->last_ic;function->fi->last_ic=p;
function->fi->vars=0;
}
if(flags&1){
local_regs(fg);
loops(fg,1);
if(DEBUG&1024) print_flowgraph(fg);
fg=create_loop_headers(fg);
if(DEBUG&1024) print_flowgraph(fg);
fg=create_loop_footers(fg);
if(DEBUG&1024) print_flowgraph(fg);
loop_regs(fg);
if(DEBUG&1024) print_flowgraph(fg);
if(flags&64){
block_regs(fg);
if(DEBUG&1024) print_flowgraph(fg);
}
insert_regs(fg);
}
if(flags&128) recalc_offsets(fg);
}
free_flowgraph(fg);
free(vilist);
FREEAV;
if((flags&32)&&gchanged&&pass>=c_flags_val[11].l) error(172,c_flags_val[11].l);
}while(gchanged&&pass<c_flags_val[11].l);
/* nur, um nochmal ueberfluessige Labels zu entfernen */
fg=construct_flowgraph();
free_flowgraph(fg);
/* Register bei Funktionsaufrufen sichern */
insert_saves();
#endif
}else{
/* keine Optimierungen */
if(flags&1) simple_regs();
}
lastlabel=label;
}